<?php
/**
 * Wrapper for making connections and queries to databases.
 * Includes some basic SELECT, INSERT, UPDATE, DELETE functions
 */
class DB {
	/**
	 * Keeps track of the number of queries made
	 *
	 * @var int $numQrys
	 */
	private $numQrys;

	/**
	 * Instance of PDO class
	 *
	 * @var PDO $db
	 */
	private $db;

	/**
	 * Path to SQLite database
	 *
	 * @var string $path
	 */
	private $path;

	/**
	 * Connects to the database located at $path
	 *
	 * @param string $path
	 */
	public function __construct ($path) {
		$this->path		= $path;
		$this->db		= new PDO("sqlite:$path") or die("Could not connect to SQLite Database: $path" . implode(', ', $this->db->errorInfo()));
		$this->numQrys	= 0;
	}

	/**
	 * Increases query count, executes $qry and returns result
	 *
	 * @param string $qry
	 */
	public function qry ($qry) {
		$this->numQrys++;

		$res = $this->db->query($qry) or die('Could not execute query: ' . str_replace("\t", '', $qry) . implode(', ', $this->db->errorInfo()));

		Logger::log("Running query #{$this->numQrys}: \"$qry\".", __METHOD__);

		return $res;
	}

	/**
	 * Escapes $str so it is safe to use in query
	 *
	 * @param string $str
	 */
	public function escSQL ($str) {
		return $this->db->quote($str);
	}

	/**
	 * Returns the ID of the last inserted row
	 */
	public function lastID () {
		return $this->db->lastInsertID();
	}

	/**
	 * Returns the number of queries
	 */
	public function getNumQrys () {
		return $this->numQrys;
	}

	/**
	 * Retrieves rows from $table based on $conf
	 *
	 * @param string $table
	 * @param array $conf
	 */
	public function get ($table, $conf = array()) {
		$config = array(
			'sort'	=> isset($conf['sort']) ? $conf['sort'] : '1', 
			'order'	=> isset($conf['order']) ? $conf['order'] : 'ASC', 
			'start'	=> isset($conf['start']) ? $conf['start'] : 0, 
			'limit'	=> isset($conf['limit']) ? $conf['limit'] : 1000000000, 
			'where'	=> isset($conf['where']) ? $conf['where'] : '1 = 1', 
			'select'=> isset($conf['select']) ? $conf['select'] : '1'
		);

		$res = $this->qry("SELECT *, {$config['select']} FROM $table WHERE {$config['where']} ORDER BY {$config['sort']} {$config['order']} LIMIT {$config['start']}, {$config['limit']};");

		if ($res) {
			$rows = array();

			while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
				$parts		= explode('_', substr($table, 0, -1));
				$parts		= array_map('ucfirst', $parts);
				$modelName	= implode('', $parts) . 'Model';
				$rows[]		= new $modelName($row);
			}

			return count($rows) > 0 ? ($config['limit'] > 1 ? $rows : $rows[0]) : false;
		}

		return false;
	}

	/**
	 * Inserts $fields into $table
	 *
	 * @param string $table
	 * @param array $fields
	 */
	public function insert ($table, $fields) {
		$insertVals = '';
		$insertCols = '';

		foreach ($fields as $col => $val) {
			if (is_numeric($val)) {
				$insertVals .= "$val,";
			}
			elseif (strtolower($val) == 'null') {
				$insertVals .= 'NULL,';
			}
			else {
				$insertVals .= self::escSQL($val) . ',';
			}

			$insertCols .= "$col,";
		}

		$insertVals = substr($insertVals, 0, -1);
		$insertCols = substr($insertCols, 0, -1);

		$this->qry("INSERT INTO $table ($insertCols) VALUES ($insertVals);");

		return $this->lastID();
	}

	/**
	 * Updates row with $id in $table with $fields
	 *
	 * @param string $table
	 * @param int $id
	 * @param array $fields
	 */
	public function update ($table, $id, $fields) {
		$updateStr = '';

		foreach ($fields as $col => $val) {
			$updateStr .= $val == 'NULL' ? "$col = NULL," : "$col = " . self::escSQL($val) . ",";
		}

		$updateStr = substr($updateStr, 0, -1);

		$this->qry("UPDATE $table SET $updateStr WHERE {$table}_id = " . self::escSQL($id) . ";");

		return true;
	}

	/**
	 * Deletes row with $id from $table
	 *
	 * @param string $table
	 * @param int $id
	 */
	public function delete ($table, $id) {
		$this->qry("DELETE FROM $table WHERE {$table}_id = " . self::escSQL($id) . ";");

		return true;
	}
}
